/**
 *@description: MY_UTILS_ASSERT为诊断宏, 修改为相应平台的诊断, 若不使用则可定义为空
 *@description: USING_STACK 等, 若不使用则需要注释掉
 *@description: my_malloc, 和 my_free 定义为相应平台的内存分配
 *@author: Kalimdorsummer
 *@date: 2020-09-28 17:40:04
*/
#ifndef MY_UTILS_H__
#define MY_UTILS_H__

#ifdef __cplusplus
extern "C" {
#endif

#include <stdlib.h>
#include <string.h>
#include "stdint.h"
#include "stdbool.h"
#include <time.h>
#include <sys/time.h>
#include <unistd.h>

#include "my_utils_support_macro.h"

#ifndef MY_UTILS_ASSERT
#define MY_UTILS_ASSERT(EX)   PT_ASSERT(EX)// do{}while(0)
#endif // MY_UTILS_ASSERT

#undef ALIGN
#define ALIGN(n)                    __attribute__((aligned(n)))


#define USING_STACK
#define USING_FIFO
#define USING_CRC
#define USING_SIZEOF_SAFE	// 使用sizeof_safe, 会增大目标文件大小, 根据实际情况开启

#ifndef MY_UNUSED
#define MY_UNUSED                   __attribute__((unused))
#endif // MY_UNUSED

#ifdef __GNUC__

// 如果绝对不是指针, 返回true
#define     NOT_PTR(x)    (\
__builtin_types_compatible_p(__typeof(x), int32_t) || \
__builtin_types_compatible_p(__typeof(x), uint32_t) || \
__builtin_types_compatible_p(__typeof(x), float ) || \
__builtin_types_compatible_p(__typeof(x), long ) || \
__builtin_types_compatible_p(__typeof(x), unsigned long ) || \
__builtin_types_compatible_p(__typeof(x), wchar_t[2] ) || \
__builtin_types_compatible_p(__typeof(x), char[4]) || \
__builtin_types_compatible_p(__typeof(x), int8_t[4]) || \
__builtin_types_compatible_p(__typeof(x), uint8_t[4]) || \
__builtin_types_compatible_p(__typeof(x), int16_t[2]) || \
__builtin_types_compatible_p(__typeof(x), uint16_t[2] ) || \
__builtin_types_compatible_p(__typeof(x), int32_t[1] ) || \
__builtin_types_compatible_p(__typeof(x), uint32_t[1] ) || \
__builtin_types_compatible_p(__typeof(x), long[1] ) || \
__builtin_types_compatible_p(__typeof(x), unsigned long[1] ) \
)

#define     SIZE_NOT_EQU_PTR(ex)    ( sizeof(ex) != sizeof(void*) )

#else
#define     NOT_PTR(x)		        true
#define     SIZE_NOT_EQU_PTR(ex)    true

#endif




//============================= 以上需要配置 ==========================================

#ifndef ATTR_PACK
#define ATTR_PACK                   __attribute__((packed))
#endif

#define memset	do_not_use_memset
#define memcpy	do_not_use_memcpy
#define strstr	do_not_use_strstr

void * memcpy_safe(void *dst, const void *src, uint32_t count, uint32_t max_len);
char * strstr_safe ( const char * s1, const char * s2, uint32_t max_len );

void * memset_safe ( void * s, int c, uint32_t count, uint32_t max_len );
void * memclear ( void * s, uint32_t count );


#define RED_SEVERE          1
#define ORANGE_HIGH         2
#define YELLOW_ELEVATED     3
#define BLUE_GUARDED        4
#define GREEN_LOW           5

// 简单测试表达式
#define CHECK_SIMP(ex, ...)       \
do{                                         \
    if(!(ex)){  \
        my_utils_log("(%s) at func:%s line:%d | ", #ex, __FUNCTION__, __LINE__); \
        my_utils_log(__VA_ARGS__); \
        my_utils_log("\n"); \
    }   \
} while(0)

// 测试失败goto到本地的标签, 例如在函数末尾添加error:
#define CHECK_LOCAL(ex, label, ...)       \
do{                                         \
    CHECK_SIMP(ex, ##__VA_ARGS__);   \
    if(!(ex)){  \
        goto label;\
    }   \
} while(0)

typedef void (*check_handler_t)(const char *ex_string, int32_t alert_lvl, const char *func, uint32_t line);
extern void set_check_handler(check_handler_t  handler);
extern check_handler_t     check_handler;
// 测试失败调用应用程序提供处理错误的回调函数cb
#define CHECK_GLOBAL(ex, alert_lvl, handler, ...)       \
do{                                         \
    CHECK_SIMP(ex, ##__VA_ARGS__);   \
    set_check_handler(handler);             \
    check_handler(#ex, alert_lvl, __FUNCTION__, __LINE__);    \
} while(0)

#ifdef __GNUC__
// 更安全版, max_len必须为常数
#define MEMSET_S(s, c, count, max_len)  \
({     \
    STATIC_ASSERT(__builtin_constant_p(max_len), "file:" __FILE__ " line:" TO_STRING(__LINE__) );   \
    memset_safe(s, c, count, max_len);      \
})

#define MEMCPY_S(dst, src, count, max_len)  \
({     \
    STATIC_ASSERT(__builtin_constant_p(max_len), "file:" __FILE__ " line:" TO_STRING(__LINE__) );   \
    memcpy_safe(dst, src, count, max_len);      \
})

#define STRSTR_S(s1, s2, max_len)  \
({     \
    STATIC_ASSERT(__builtin_constant_p(max_len), "file:" __FILE__ " line:" TO_STRING(__LINE__) );   \
    strstr_safe(s1, s2, max_len);      \
})
#else
#define MEMSET_S(s, c, count, max_len)          memset_safe(s, c, count, max_len)
#define MEMCPY_S(dst, src, count, max_len)      memcpy_safe(dst, src, count, max_len)
#define STRSTR_S(s1, s2, max_len)               strstr_safe(s1, s2, max_len)
#endif // __GNUC__

#ifdef __GNUC__
// 获取ex大小前先检测是否可能为指针, 对于sizeof(ptr), 可能不是开发者想要的
// C语言没有好的检查是指针的方法, 这里判断传入参数是否为基本的类型(4字节, 仅可用于32位系统)
#ifdef USING_SIZEOF_SAFE
#ifndef __cplusplus
#define sizeof_safe(ex)	\
({	/*若该类型不在罗列的类型中, 而且长度和指针一样那就算指针*/\
    STATIC_ASSERT( NOT_PTR(ex) || SIZE_NOT_EQU_PTR(ex) , "file:" __FILE__ " line:" TO_STRING(__LINE__) " should not use ptr");   \
	sizeof(ex);	\
})
#else
#define sizeof_safe(ex)	\
({	\
    static_assert(!std::is_pointer<__typeof(ex)>::value, "file:" __FILE__ ", line:" TO_STRING(__LINE__) " should not use ptr");   \
	sizeof(ex);	\
})
#endif
#else
#define sizeof_safe(ex)		sizeof(ex)
#endif

#else
#define sizeof_safe(ex)		sizeof(ex)
#endif

uint32_t reverse_byte(uint32_t val, uint8_t num);

bool DATE_TIME_to_tm(struct tm *p_tm, char *date, char *time_);


//================== 转换操作 ========================
unsigned char AscToHex ( char h, char l );
int StrToHex ( char * p_hex, char * p_str, int len, int hex_len );
int HexToChar ( unsigned char * p_char, unsigned char * p_hex, int len, int char_len );
int HexToStr ( unsigned char * p_str, unsigned char * p_hex, int len, int str_len );


#ifndef linux
//================== 转换操作 end ========================
// 测试位
static inline bool test_bit(uint32_t num, uint32_t bit_cnt)
{
	if(num & (1 << bit_cnt) ){
		return true;
	}

	return false;

}
#endif

//================= 栈操作 ========================
// 必须使用stack_create动态创建或者DEFINE_STACK静态定义, 静态定义需要调用statck_init初始化
#ifdef USING_STACK

#define STACK_STATUS_OK     0X0000
#define STACK_STATUS_ERR    0X00F0
#define STACK_PARAM_NULL    0X00F1
#define STACK_FULL          0X00A0
#define STACK_EMPTY         0X00B0


#define STACK_STRUCT_SIZE    ( sizeof(size_t) * 3 ) // stack结构体的字节数
typedef struct stack_cover*	stack_t;	// 一层封皮, 用于检测输入参数类型是否匹配, 不匹配编译器可给出警告

stack_t stack_create(size_t stack_size, size_t element_size);
void stack_init(stack_t pv_s, size_t element_max, size_t element_size);
void stack_destroy(stack_t pv_s);
void stack_make_empty(stack_t pv_s);
bool stack_is_empty(stack_t pv_s);
bool stack_is_full(stack_t pv_s);
int32_t stack_push(stack_t pv_s, void *in);
int32_t stack_pop(stack_t pv_s, void *out);

size_t stack_max_element(stack_t pv_s);

// 静态定义stack, name直接是指针, 不需要&访问
// 为了使buf紧跟在stack_ins后, 打包定义
#define DEFINE_STACK(name, element_max, element_type)    \
struct name##stack_and_buf{               \
    uint32_t        stack_ins[STACK_STRUCT_SIZE / sizeof(uint32_t)];          \
    uint8_t         buf[element_max * sizeof(element_type)];    \
}ATTR_PACK;  \
struct name##stack_and_buf name##_stack_whole = {   \
    .stack_ins = {  0, \
                    element_max * sizeof(element_type), \
                    sizeof(element_type)    \
                 }, \
};\
const stack_t name = (stack_t)&name##_stack_whole.stack_ins;


#define DECLARE_STACK(name) \
extern const stack_t name;
#endif
//================= 栈操作 end ========================

//================= fifo 操作 =========================
// 必须使用fifo_create动态创建或者DEFINE_FIFO静态定义, 静态定义需要调用fifo_init初始化
#ifdef USING_FIFO
#define FIFO_STATUS_OK      0X00
#define FIFO_STATUS_ERR     0XF0
#define FIFO_PARAM_INVAL    0XF1    // 参数无效

#define FIFO_FULL           0XA0
#define FIFO_EMPTY          0XB0
#define FIFO_HALF           0XC0


#define FIFO_STRUCT_SIZE    ( sizeof(size_t) * 8) // fifo结构体的字节数

typedef struct fifo_cover*	fifo_t;	// 一层封皮, 用于检测输入参数类型是否匹配, 不匹配编译器可给出警告


int32_t fifo_init(fifo_t pv_fifo, size_t element_max, size_t element_size);
fifo_t fifo_create(size_t element_max, size_t element_size);
void fifo_destroy(fifo_t pv_fifo);
size_t fifo_putf(fifo_t  pv_fifo, const void * in_val);
size_t fifo_put(fifo_t pv_fifo, const void * in_val);
size_t fifo_get ( fifo_t  pv_fifo, void * out_val );
size_t fifo_writef(fifo_t pv_fifo, void const * p_data_in, size_t cnt);
size_t fifo_write(fifo_t  pv_fifo, void const * p_data_in, size_t cnt);
size_t fifo_read( fifo_t  pv_fifo, void * p_data_out, size_t cnt);

uint16_t get_clr_fifo_errno(fifo_t pv_fifo);
void clr_fifo_errno(fifo_t pv_fifo);
uint16_t get_fifo_errno(fifo_t pv_fifo);
uint32_t get_fifo_element_cnt(fifo_t pv_fifo);
uint32_t get_fifo_status(fifo_t pv_fifo);
void fifo_flush(fifo_t pv_fifo);
void fifo_peek(fifo_t pv_fifo, size_t index, void * out);

size_t fifo_max_element(fifo_t pv_fifo);

// 定义fifo, name直接是指针, 不需要&访问
// 定义后即可使用
#define DEFINE_FIFO(name, element_max, element_type)    \
struct name##fifo_and_buf{     \
    uint32_t        fifo_ins[FIFO_STRUCT_SIZE / sizeof(uint32_t)]; /*fifo_t隐藏起来了, 只能定义一块内存区域, 无法得知类型*/ \
    uint8_t         buf[element_max * sizeof(element_type)];    \
}ALIGN(4) ATTR_PACK;\
struct name##fifo_and_buf     name##_fifo_whole = { \
    .fifo_ins = {   sizeof(element_type) * element_max,  \
                    0,  \
                    0,  \
                    element_max,    \
                    sizeof(element_type),   \
                    0,  \
                    0,  \
                    FIFO_EMPTY},  \
};\
const fifo_t name = (fifo_t)&name##_fifo_whole.fifo_ins;

#define DECLARE_FIFO(name) \
extern const fifo_t name;
#endif


//================= fifo 操作 end =========================


//================= array 操作 ============================
typedef enum {
    container_type_array = 0x100,
    container_type_vector,
    container_type_deque,

}container_type;
//#pragma GCC diagnostic push
//#pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
//#pragma GCC diagnostic pop
#define ARRAY_HEAD \
 	size_t              size;   \
 	size_t              resv;   /*占据空间, 使8字节对齐*/  \
 	container_type      ctn_type;
// 内部用
struct array_common_s{
    ARRAY_HEAD;
	char        array_buffer[];
};
#define ARRAY_PRINTF(...)      //printf(__VA_ARGS__)

typedef void*   array_t;

#define array_type(TYPE)    \
struct {  \
    ARRAY_HEAD; \
    __typeof(TYPE) array_buffer[]; \
} *

// 定义数组实例
#define DEFINE_ARRAY(array_name, TYPE, element_max)  \
struct {  \
    ARRAY_HEAD; \
    __typeof(TYPE) array_buffer[element_max]; \
}array_name##_whole = {  \
    .size = element_max,  \
    .ctn_type = container_type_array,   \
}; \
__typeof(array_name##_whole) *array_name = (__typeof(array_name##_whole) *)&array_name##_whole; \

// 定义向量实例, 有初始化值
#define DEFINE_ARRAY_INIT(array_name, TYPE, ...)  \
TYPE array_name##_init_data[] = GET_ARGS(__VA_ARGS__);  \
struct {  \
    ARRAY_HEAD; \
    __typeof(TYPE) array_buffer[SIZEOF_ARR(array_name##_init_data)]; \
}array_name##_whole = {  \
    .size = SIZEOF_ARR(array_name##_init_data),  \
    .ctn_type = container_type_array,   \
    .array_buffer = GET_ARGS(__VA_ARGS__),  \
}; \
__typeof(array_name##_whole) *array_name = (__typeof(array_name##_whole) *)&array_name##_whole; \




// 定义在结构体或类中
#define DEFINE_ARRAY_INCLASS(array_name, TYPE, element_max)  \
array_adt_##TYPE##_t array_name;    /*只是为了占据空间*/\
TYPE array_name##_array_buffer[element_max]; \

void array_init_$(void *pv_array, size_t element_max);
#define array_init(pv_array, element_max) \
({  \
    array_init_$(pv_array, element_max);    \
})


void *array_create_$(size_t element_max, size_t element_size);
#define array_create(element_max, TYPE) \
({  \
    void    *p_ret_in_array_create;  \
    p_ret_in_array_create = array_create_$(element_max, sizeof(TYPE) );  \
    p_ret_in_array_create;  \
})

void array_destroy_$(void *pv_array);
#define array_destroy(pv_array) \
({  \
    array_destroy_$(pv_array);  \
    pv_array = (__typeof(pv_array) )0;  \
})

void *array_at_$(void *pv_array, size_t idx, size_t element_size);
#define array_at_(pv_array, idx) \
({  \
    __typeof( (pv_array)->array_buffer[0])     *p_ref_in_array_at = (void*)0;  \
    p_ref_in_array_at = array_at_$( (pv_array), (idx), sizeof( (pv_array)->array_buffer[0]) );   \
    p_ref_in_array_at; \
})
#define array_at( pv_array , idx)    ( *array_at_( (pv_array), (idx) ) )

#define array_front( pv_array )   \
({  \
    __typeof((pv_array)->array_buffer[0])     ret_val_in_array_front; \
    ret_val_in_array_front = array_at(pv_array, 0); \
    ret_val_in_array_front; \
})

#define array_back(pv_array)   \
({  \
    __typeof((pv_array)->array_buffer[0])     ret_val_in_array_back; \
    ret_val_in_array_back = array_at(pv_array, ((pv_array)->size - 1) ); \
    ret_val_in_array_back; \
})

void array_fill_$(void *pv_array, void *fill_val, size_t element_size);
#define array_fill(pv_array, fill_val_by_value) \
({  \
    __typeof((pv_array)->array_buffer[0])     tmp_val_in_array_fill = fill_val_by_value; \
    array_fill_$(pv_array, &tmp_val_in_array_fill, sizeof((pv_array)->array_buffer[0]) ); \
})


#define array_clear(pv_array)   \
({  \
    size_t size_in_array_clear = (pv_array)->size * sizeof((pv_array)->array_buffer[0]); \
    memset((pv_array)->array_buffer, 0, size_in_array_clear); \
})

#define array_data(pv_array)    \
({  \
    __typeof((pv_array)->array_buffer[0])     *p_data_in_array_data = &(pv_array)->array_buffer[0]; \
    p_data_in_array_data;   \
})

// 数组迭代器
#define array_itor(pv_array)    \
__typeof((pv_array)->array_buffer[0])   *

#define array_citor(pv_array)   \
__typeof((pv_array)->array_buffer[0]) * const

#define array_begin(pv_array)   array_data(pv_array)

#define array_end(pv_array)     \
({  \
    __typeof((pv_array)->array_buffer[0])     *p_end_in_array_end = array_begin(pv_array) + array_size(pv_array);   \
    p_end_in_array_end; \
})


size_t array_size(void * pv_array);


// 拷贝, 只能用array adt类型, 普通数组类型容易越界
#define arr_copy(dest_arr, src_arr, cpy_cnt)    \
({  \
    size_t cnt_in_arr_copy = cpy_cnt;   \
    MY_UTILS_ASSERT( cnt_in_arr_copy <= array_size(dest_arr) );  \
    for (size_t i = 0; i < cnt_in_arr_copy; i++){   \
        array_at(dest_arr, i) = array_at(src_arr, i);   \
    }   \
})


struct arr2d_common_s{
 	size_t      row;
 	size_t      col;
	char        array_buffer[][0];
};

// 定义数组实例
#define DEFINE_ARR2D(array_name, TYPE, row_ele_max, col_ele_max)  \
struct {  \
    size_t      row;   \
    size_t      col;    \
    __typeof(TYPE) array_buffer[row_ele_max][col_ele_max]; \
}array_name##_whole = {  \
    .row = row_ele_max,     \
    .col = col_ele_max,     \
}; \
__typeof(array_name##_whole) *array_name = (__typeof(array_name##_whole) *)&array_name##_whole; \

void *arr2d_at_$(void *pv_array, size_t row, size_t col, size_t element_size);
#define arr2d_at_(pv_array, row, col) \
({  \
    __typeof((pv_array)->array_buffer[0][0])     *p_ref_in_array_at = (void*)0;  \
    p_ref_in_array_at = arr2d_at_$(pv_array, (row), (col), sizeof((pv_array)->array_buffer[0][0]) );   \
    p_ref_in_array_at; \
})
#define arr2d_at(pv_array, row, col)    ( *arr2d_at_(pv_array, (row), (col) ) )

void arr2d_fill_$(void *pv_array, void *fill_val, size_t element_size);
#define arr2d_fill(pv_array, fill_val_by_value) \
({  \
    __typeof((pv_array)->array_buffer[0][0])     tmp_val_in_array_fill = fill_val_by_value; \
    arr2d_fill_$(pv_array, &tmp_val_in_array_fill, sizeof((pv_array)->array_buffer[0][0]) ); \
})

size_t arr2d_row(void * pv_array);
size_t arr2d_col(void * pv_array);

//================= array 操作 end ========================

//================= vector 操作 ===========================


#define VECTOR_HEAD \
 	size_t              size;   \
 	size_t              capacity;  \
 	int32_t             not_heap;   \
 	container_type      ctn_type;   \


// 若定义在结构体中, 需要手动调用init和destroy
#define DEFINE_VEC_IN_STRUCT(vector_name, TYPE) \
struct {  \
    VECTOR_HEAD \
    __typeof(TYPE) *vector_buffer; \
}vector_name;

// 定义向量实例
#define DEFINE_VECTOR(vector_name, TYPE)  \
struct {  \
    VECTOR_HEAD \
    __typeof(TYPE) *vector_buffer; \
}vector_name##_whole = {  \
    .size = 0,  \
    .capacity = 0,  \
    .not_heap = 0,  \
    .ctn_type = container_type_vector,  \
    .vector_buffer = NULL,  \
}; \
__typeof(vector_name##_whole) *vector_name AUTO_CLEAN_UP(vec_cleanup) = (__typeof(vector_name##_whole) *)&vector_name##_whole; \

// 定义向量实例, 有初始化值
#define DEFINE_VECTOR_INIT(vector_name, TYPE, ...)  \
TYPE vector_name##_init_data[] = GET_ARGS(__VA_ARGS__);  \
struct {  \
    VECTOR_HEAD \
    __typeof(TYPE) *vector_buffer; \
}vector_name##_whole = {  \
    .size = SIZEOF_ARR(vector_name##_init_data),  \
    .capacity = SIZEOF_ARR(vector_name##_init_data),  \
    .not_heap = 1,  \
    .ctn_type = container_type_vector,  \
    .vector_buffer = vector_name##_init_data,  \
}; \
__typeof(vector_name##_whole) *vector_name AUTO_CLEAN_UP(vec_cleanup) = (__typeof(vector_name##_whole) *)&vector_name##_whole; \



void vec_cleanup(const void *v);

struct vector_common_s{
    VECTOR_HEAD;
	char        *vector_buffer;
};


#define VECTOR_PRINTF   my_utils_log


#define vec_push_back(pv_vec, in_val)   \
({  \
    __typeof(pv_vec->vector_buffer[0])  tmp_in_vec_push_back = in_val;   \
    vec_push_back_$(pv_vec, &tmp_in_vec_push_back, sizeof(tmp_in_vec_push_back));  \
})


#define vec_pop_back(pv_vec)   \
({  \
    __typeof(pv_vec->vector_buffer[0])  tmp_in_vec_pop_back;   \
    vec_pop_back_$(pv_vec, &tmp_in_vec_pop_back, sizeof(tmp_in_vec_pop_back));  \
    tmp_in_vec_pop_back;    \
})


#define vec_resize(pv_vec, new_size)    vec_resize_$(pv_vec, new_size, sizeof_safe(pv_vec->vector_buffer[0]) );

#define vec_reserve(pv_vec, new_cap)    vec_reserve_$(pv_vec, new_cap, sizeof_safe(pv_vec->vector_buffer[0]) )


#define vec_data(pv_vec)    \
({  \
    __typeof((pv_vec)->vector_buffer[0])     *p_data_in_vec_data = &(pv_vec)->vector_buffer[0]; \
    p_data_in_vec_data;   \
})

#define vec_begin(pv_vec)   vec_data(pv_vec)

#define vec_end(pv_vec) \
({  \
    __typeof((pv_vec)->vector_buffer[0])     *p_data_in_vec_data = vec_begin(pv_vec) + vec_size(pv_vec);    \
    p_data_in_vec_data; \
})


#define vec_at(pv_vec, idx) \
({  \
    __typeof((pv_vec)->vector_buffer[0])     *p_data_in_vec_at = vec_at_$(pv_vec, idx, sizeof_safe((pv_vec)->vector_buffer[0]));   \
    *p_data_in_vec_at;  \
})

#define vec_front(pv_vec)   vec_at(pv_vec, 0)

#define vec_back(pv_vec)    vec_at(pv_vec, vec_size(pv_vec) - 1)


#define vec_shrink_to_fit(pv_vec)   vec_shrink_to_fit_$( pv_vec, sizeof_safe(pv_vec->vector_buffer[0]) )


#define vec_insert(pv_vec, itor, in_val)    \
({  \
    __typeof( (pv_vec)->vector_buffer[0])   tmp_in_vec_insert = in_val; \
    __typeof(itor)   ret_itor_in_vec_insert; \
    ret_itor_in_vec_insert = vec_insert_$(pv_vec, itor, &tmp_in_vec_insert, sizeof_safe(tmp_in_vec_insert) );    \
    ret_itor_in_vec_insert; \
})


#define vec_erase(pv_vec, itor) \
({  \
    vec_itor(pv_vec) ret_it_in_vec_erase = vec_erase_$(pv_vec, itor, sizeof_safe(pv_vec->vector_buffer[0]));   \
    ret_it_in_vec_erase;    \
})

#define vec_empty(pv_vec)   vec_empty_$(pv_vec)

#define vec_reverse(pv_vec, vbegin, vend)   \
({  \
     vec_reverse_$(pv_vec, vbegin, vend, sizeof_safe(pv_vec->vector_buffer[0]) );   \
})



// 向量迭代器
#define vec_itor(pv_vec)    __typeof((pv_vec)->vector_buffer[0])   *

size_t vec_size(void * pv_vec);
size_t vec_capacity(void * pv_vec);
void vec_push_back_$(void *pv_vec, void *in_val, size_t element_size);
void vec_pop_back_$(void *pv_vec, void *out_val, size_t element_size);
void vec_resize_$(void *pv_vec, size_t new_size, size_t element_size);
void vec_reserve_$(void *pv_vec, size_t new_cap, size_t element_size);
void vec_clear(void *pv_vec);
void *vec_at_$(void *pv_vec, size_t idx, size_t element_size);
void vec_shrink_to_fit_$(void *pv_vec, size_t element_size);
void * vec_insert_$(void *pv_vec, void *itor, void *in_val, size_t element_size);
void * vec_erase_$(void *pv_vec, void *itor, size_t element_size);
bool vec_empty_$(void *pv_vec);
void vec_reverse_$(void *pv_vec, void *vbegin, void *vend, size_t element_size);


void vec_init(void *pv_vec);
void vec_destroy(void *pv_vec);

//================= vector 操作 end =======================

//================= string 操作 =======================
struct string_s{
    VECTOR_HEAD
    char *vector_buffer;
};

typedef struct string_s* string_t;

enum string_e{
    old_c_string_type = 0x58,   // char *型字符串
    new_string_s_type = 0xa9,   // 新型封装的字符串
};

// 定义string实例
#define DEFINE_STRING(string_name)  \
struct string_s string_name##_whole = {  \
    .size = 0,  \
    .capacity = 0,  \
    .not_heap = 0,  \
    .ctn_type = container_type_vector,  \
    .vector_buffer = NULL,  \
}; \
struct string_s *string_name AUTO_CLEAN_UP(vec_cleanup) = &string_name##_whole; \


// 定义string, 带有初始化"0123456"这样的字符串
#define DEFINE_STRING_INIT(string_name, ...) \
char string_name##_init_data[] = GET_ARGS(__VA_ARGS__);  \
struct string_s string_name##_whole = {  \
    .size = SIZEOF_ARR(string_name##_init_data),  \
    .capacity = SIZEOF_ARR(string_name##_init_data),  \
    .not_heap = 1,  \
    .ctn_type = container_type_vector,  \
    .vector_buffer = string_name##_init_data,  \
}; \
__typeof(string_name##_whole) *string_name AUTO_CLEAN_UP(vec_cleanup) = (__typeof(string_name##_whole) *)&string_name##_whole; \


#define string_len(pv_string)       \
({  \
    size_t ret_in_string_len = vec_size(pv_string);   \
    if( ret_in_string_len > 0){    \
        ret_in_string_len -= 1; \
    }   \
    ret_in_string_len;  \
})


#define string_assign(pv_string, ...)    \
({  \
    string_assign_$(pv_string, GET_ARGS(__VA_ARGS__), get_string_type(GET_ARGS(__VA_ARGS__)));  \
})

#define string_c_str(pv_string)   vec_data(pv_string)

#define string_at(pv_string, idx)   vec_at(pv_string, idx)

#define get_string_type(check_string)    \
({  \
    enum string_e tmp_in_get_string_type; \
    if(types_cmp_p( __typeof(check_string), __typeof(string_t) ) ){    \
        tmp_in_get_string_type = new_string_s_type;  \
    }else{  \
        tmp_in_get_string_type = old_c_string_type;  \
    }   \
    tmp_in_get_string_type;   \
})
#define string_append(pv_src, ...)    \
({  \
    for(int i = 1; i <= MY_NUM_VA_ARGS(__VA_ARGS__); i++){   \
        switch(i){  \
            case 1: \
                string_append_$(pv_src, get_nth_param_1(__VA_ARGS__, "no_use", "no_use", "no_use", "no_use", "no_use", "no_use"), get_string_type(get_nth_param_1(__VA_ARGS__, "no_use", "no_use", "no_use", "no_use", "no_use", "no_use")) ); \
            break;  \
            case 2: \
                string_append_$(pv_src, get_nth_param_2(__VA_ARGS__, "no_use", "no_use", "no_use", "no_use", "no_use", "no_use"), get_string_type(get_nth_param_2(__VA_ARGS__, "no_use", "no_use", "no_use", "no_use", "no_use", "no_use")) ); \
            break;  \
            case 3: \
                string_append_$(pv_src, get_nth_param_3(__VA_ARGS__, "no_use", "no_use", "no_use", "no_use", "no_use", "no_use"), get_string_type(get_nth_param_3(__VA_ARGS__, "no_use", "no_use", "no_use", "no_use", "no_use", "no_use")) ); \
            break;  \
            case 4: \
                string_append_$(pv_src, get_nth_param_4(__VA_ARGS__, "no_use", "no_use", "no_use", "no_use", "no_use", "no_use"), get_string_type(get_nth_param_4(__VA_ARGS__, "no_use", "no_use", "no_use", "no_use", "no_use", "no_use")) ); \
            break;  \
            case 5: \
                string_append_$(pv_src, get_nth_param_5(__VA_ARGS__, "no_use", "no_use", "no_use", "no_use", "no_use", "no_use"), get_string_type(get_nth_param_5(__VA_ARGS__, "no_use", "no_use", "no_use", "no_use", "no_use", "no_use")) ); \
            break;  \
            case 6: \
                string_append_$(pv_src, get_nth_param_6(__VA_ARGS__, "no_use", "no_use", "no_use", "no_use", "no_use", "no_use"), get_string_type(get_nth_param_6(__VA_ARGS__, "no_use", "no_use", "no_use", "no_use", "no_use", "no_use")) ); \
            break;  \
            default:    \
                break;  \
        }   \
    }   \
})


#define string_erase(pv_string, pos, ...)   \
({  \
    if(MY_NUM_VA_ARGS(__VA_ARGS__) == 0){   \
        string_erase_$(pv_string, pos, vec_size(pv_string) - pos);  \
    }else{  \
        size_t cnt_in_string_erase = GET_ARGS(__VA_ARGS__) + 0; \
        string_erase_$(pv_string, pos, cnt_in_string_erase);    \
    }   \
})


#define string_insert(pv_string, pos, new_string)       string_insert_$(pv_string, pos, new_string)


#define string_compare(pv_string, cmp_string)   \
({  \
    string_compare_$(pv_string, cmp_string, get_string_type(cmp_string)); \
})


void string_assign_$(void *pv_string, void *new_string, enum string_e string_type);
void string_append_$(void *pv_src, void *new_string, enum string_e string_type);
void string_erase_$(void *pv_string, size_t pos, size_t cnt);
void string_insert_$(void *pv_string, size_t pos, void *new_string, enum string_e string_type);
int string_compare_$(void *pv_string, void *cmp_string, enum string_e string_type);

//================= string 操作 end =======================

//================= deque 操作 ============================
#define DEQUE_HEAD \
 	size_t              size;   \
 	size_t              element_size;   \
 	size_t              capacity;  \
 	int32_t             not_heap;   \
 	container_type      ctn_type;   \


// 定义向量实例
#define DEFINE_DEQUE(deque_name, TYPE)  \
struct {  \
    DEQUE_HEAD \
    __typeof(TYPE) *deque_buffer; \
    int         head_idx;   \
    int         tail_idx;   \
}deque_name##_whole = {  \
    .size = 0,  \
    .element_size = sizeof(TYPE),   \
    .capacity = 0,  \
    .not_heap = 0,  \
    .ctn_type = container_type_deque,  \
    .deque_buffer = NULL,  \
    .head_idx = -1, \
    .tail_idx = 0, \
}; \
__typeof(deque_name##_whole) *deque_name = (__typeof(deque_name##_whole) *)&deque_name##_whole; \

struct deque_common_s{
    DEQUE_HEAD;
    char        *deque_buffer;
    int         head_idx;
    int         tail_idx;
};


#define deq_push_back(pv_deq, in_val)   \
({  \
    __typeof(pv_deq->deque_buffer[0])  tmp_in_deq_ush_back = in_val;   \
    deq_push_back_$(pv_deq, &tmp_in_deq_ush_back);  \
})

#define deq_pop_back(pv_deq)   \
({  \
    __typeof(pv_deq->deque_buffer[0])  tmp_in_deq_pop_back;   \
    deq_pop_back_$(pv_deq, &tmp_in_deq_pop_back);  \
    tmp_in_deq_pop_back;    \
})

#define deq_push_front(pv_deq, in_val)   \
({  \
    __typeof(pv_deq->deque_buffer[0])  tmp_in_deq_push_front = in_val;   \
    deq_push_front_$(pv_deq, &tmp_in_deq_push_front);  \
})

#define deq_pop_front(pv_deq)   \
({  \
    __typeof(pv_deq->deque_buffer[0])  tmp_in_deq_pop_front;   \
    deq_pop_front_$(pv_deq, &tmp_in_deq_pop_front);  \
    tmp_in_deq_pop_front;    \
})

#define deq_resize(pv_deq, new_size)  \
({  \
    MY_UTILS_ASSERT(pv_deq->ctn_type == container_type_deque);  \
    deq_resize_$(pv_deq, new_size); \
})


#define deq_at(pv_deq, idx)     *(__typeof((pv_deq)->deque_buffer[0]) *)deq_at_$(pv_deq, idx)

#define deq_front(pv_deq)   deq_at(pv_deq, 0)

#define deq_back(pv_deq)    deq_at(pv_deq, deq_size(pv_deq) - 1)

#define deq_begin(pv_deq)   (__typeof((pv_deq)->deque_buffer[0]) *)deq_at_$(pv_deq, 0)

// at限制了idx, 因此先获取前一个再加1
#define deq_end(pv_deq)     ( (__typeof((pv_deq)->deque_buffer[0]) *)deq_at_$(pv_deq, deq_size(pv_deq) - 1) + 1)

#define deq_shrink_to_fit(pv_deq)   \
({  \
    MY_UTILS_ASSERT(pv_deq->ctn_type == container_type_deque);  \
    deq_shrink_to_fit_$(pv_deq);    \
})
size_t deq_size(void * pv_deq);
size_t deq_capacity(void * pv_deq);
void deq_push_back_$(void *pv_deq, void *in_val);
void deq_pop_back_$(void *pv_deq, void *out_val);
void deq_push_front_$(void *pv_deq, void *in_val);
void deq_pop_front_$(void *pv_deq, void *out_val);
void deq_clear(void *pv_deq);
bool deq_empty(void *pv_deq);
void deq_resize_$(void *pv_deq, size_t new_size);
void *deq_at_$(void *pv_deq, size_t idx);
void deq_shrink_to_fit_$(void *pv_deq);




//================= deque 操作 end ========================

//================= find 操作 =============================
typedef bool (*find_if_pre_t)(void *obs);
void *find_if_$(void *vbegin, void *vend, find_if_pre_t func, size_t element_size);
void *find_$(void *vbegin, void *vend, void *target, size_t element_size);

#define find_if(vbegin, vend, func) \
({  \
    STATIC_ASSERT(types_cmp_p(__typeof(vbegin), __typeof(vend) ), "file:" __FILE__ " line:" TO_STRING(__LINE__) " must be same type" ); \
    __typeof(vbegin)  ret_in_find_if;    \
    ret_in_find_if = find_if_$(vbegin, vend, func, sizeof(*vbegin) );  \
    ret_in_find_if; \
})

#define find(vbegin, vend, target)      \
({  \
     STATIC_ASSERT(types_cmp_p(__typeof(vbegin), __typeof(vend) ), "file:" __FILE__ " line:" TO_STRING(__LINE__) " must be same type" ); \
    __typeof(vbegin)  ret_in_find;   \
    __typeof(*vbegin)  target_in_find = target;   \
    ret_in_find = find_$(vbegin, vend, &target_in_find, sizeof_safe(*vbegin) ); \
    ret_in_find;    \
})

//================= find 操作 end =============================

//================= for_each 操作 =============================
typedef void (*for_each_func_t)(void *ele);

#define for_each(vbegin, vend, func)    \
({  \
    for_each_$(vbegin, vend, func, sizeof(*vbegin) );   \
})

void for_each_$(void *vbegin, void *vend, for_each_func_t   func, size_t element_size);
//================= for_each 操作 end =============================

//================== 常用内建函数宏定义 ========================
#ifdef __GNUC__
/**
 *	x中1的个数
 */
#define popcount(s) __builtin_popcount(s)

/**
 *	x中1的奇偶性。
 *	奇:1, 偶:0
 */
#define parity(i) __builtin_parity(i)

/**
 *	当前函数的第n级调用者的地址，用的最多的就是__builtin_return_address(0)，
 *	即获得当前函数的调用者的地址。
 *	注意，该函数实现是体系结构相关的，有些体系结构只实现了n=0的返回结果。
 */
#define return_addr(s) __builtin_return_address(s)

/**
 *	按字节翻转x，返回翻转后的结果。
 *	uint16_t __builtin_bswap16 (uint16_t x)
 *	uint32_t __builtin_bswap32 (uint32_t x)
 */
#define swap16(i) __builtin_bswap16(i)
#define swap32(i) __builtin_bswap32(i)

/**
 *	判断exp是否在编译时就可以确定其为常量，
 *	如果exp为常量，该函数返回1，否则返回0。
 *	如果exp为常量，可以在代码中做一些优化来减少处理exp的复杂度
 */
#define constant_p(exp) __builtin_constant_p(exp)

/**
 *	判断type1和type2是否是相同的数据类型，相同返回1，否则返回0。
 *	该函数不区分const/volatile这样的修饰符，即int和const int被认为是相同的类型
 */
#define types_cmp_p(t1, t2) __builtin_types_compatible_p(t1, t2)

#elif defined(__CC_ARM)

#define return_addr(s) 		__return_address()
#define swap32(i) 			__rev(i)

#endif // __GNUC__

//================== 常用内建函数宏定义 end ========================


//================== 通用小函数或宏 =============================
// 获取数组元素个数
#undef SIZEOF_ARR
#define SIZEOF_ARR(arr)     ( (size_t)( sizeof(arr) / sizeof(arr[0]) ) )

#undef SIZEOF_ARR_S
#define SIZEOF_ARR_S(arr)     ( (size_t)( sizeof_safe(arr) / sizeof_safe(arr[0]) ) )


#ifdef __GNUC__
#ifndef MAX
#define MAX(x, y) ({            \
    __typeof(x) _x_in_MAX_99unique = x;         \
    __typeof(y) _y_in_MAX_99unique = y;         \
    (void) ( &_x_in_MAX_99unique == &_y_in_MAX_99unique );      \
    _x_in_MAX_99unique >_y_in_MAX_99unique ? _x_in_MAX_99unique : _y_in_MAX_99unique;           \
})
#endif // MAX

#ifndef MIN
#define MIN(x, y) ({            \
    __typeof(x) _x_in_MIN = x;         \
    __typeof(y) _y_in_MIN = y;         \
    (void) ( &_x_in_MIN == &_y_in_MIN );      \
    _x_in_MIN >_y_in_MIN ? _y_in_MIN : _x_in_MIN;           \
})

#undef MATH_SAT
#define MATH_SAT(val, sat_up, sat_down) \
({  \
    __typeof(val) _ret_val_in_MATH_SAT = val;    \
    __typeof(val) _sat_up_in_MATH_SAT = sat_up;    \
    __typeof(val) _sat_down_in_MATH_SAT = sat_down;    \
    if (val > (_sat_up_in_MATH_SAT) ){  \
        _ret_val_in_MATH_SAT = (_sat_up_in_MATH_SAT);   \
    }else if (val < (_sat_down_in_MATH_SAT)){   \
        _ret_val_in_MATH_SAT = (_sat_down_in_MATH_SAT); \
    }   \
    _ret_val_in_MATH_SAT;    \
})
#endif // MIN
#else

#ifndef MAX
#define MAX(x,y)     ( (x) > (y)?(x):(y) )
#endif // MAX

#ifndef MIN
#define MIN(x,y)     ( (x) > (y)?(y):(x) )
#endif // MIN

#endif // __GNUC__

#ifndef __GNUC__

#ifndef SWAP
#define SWAP(a, b)  \
do{     \
    unsigned char temp_in_SWAP_99percent_unique[8];              \
    memcpy(temp_in_SWAP_99percent_unique, &a, sizeof(a));  \
    memcpy(&a, &b, sizeof(a));  \
    memcpy(&b, temp_in_SWAP_99percent_unique, sizeof(a));  \
    (void) ( &a == &b );    \
}while(0)
#endif // SWAP

#else

#ifndef SWAP
#define SWAP(a, b)  \
do{                                                 \
    __typeof(a)  temp_in_SWAP_99percent_unique;               \
    temp_in_SWAP_99percent_unique = a;   \
    a = b;      \
    b = temp_in_SWAP_99percent_unique;   \
    (void) ( &a == &b );  \
}while(0)
#endif // SWAP

// 数组反向
#define INVERSE_ARR(data_in, data_cnt)  \
({  \
    int inv_start_in_INVERSE_ARR = 0;  \
    int inv_end_in_INVERSE_ARR = data_cnt - 1; \
    while(inv_start_in_INVERSE_ARR < inv_end_in_INVERSE_ARR){ \
        SWAP(data_in[inv_start_in_INVERSE_ARR], data_in[inv_end_in_INVERSE_ARR]); \
        inv_start_in_INVERSE_ARR++; \
        inv_end_in_INVERSE_ARR--;  \
    }   \
})

#endif // __GNUC__




// 判断是否奇数
static inline bool is_odd(uint32_t x)
{
    return (x & 0x01);
}

static inline bool is_even(uint32_t x)
{
    return !is_odd(x);
}

void gen_bswap(void *p_val, size_t size);

// 判断是否为2的次幂
#define is_power_of_2(n) ((n) != 0 && ((n) & ((n) - 1)) == 0)

// 将一个数向上取整为2的幂
static inline unsigned int next_pow2(unsigned int v) {
    --v;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    return ++v;
}
// 定义二维指针, 其实row没有用, 只是方便使用
// 例如:
// int DEFINE_2D_PTR(p2d_arr, 4, 3);    // 可以把p2d_arr当做二维数组访问, p2d_arr[1][2] = 7;
#define DEFINE_2D_PTR(name, row, column)    \
(*name) [column];

#ifdef __GNUC__
// 获取二维数组的类型, 可用于定义指向二维数组的指针
// 例如:
//  int a[4][3];
//  TYPEOF_2D_ARR(a) *p_a = a;
#define TYPEOF_2D_ARR(_2d_arr)   \
__typeof(_2d_arr[0])
#endif // __GNUC__

// 用一个值填充数组
#define FILL_ARR(arr, value, fill_cnt, max_cnt)    \
do{ \
    size_t _fill_cnt_in_FILL_ARR = fill_cnt;    \
    if(_fill_cnt_in_FILL_ARR > max_cnt){    \
        _fill_cnt_in_FILL_ARR = max_cnt;    \
    }   \
    for(size_t i = 0; i < _fill_cnt_in_FILL_ARR; i++){  \
        arr[i] = value; \
    }   \
}while(0)

// 用一个值填充二维数组
#define FILL_ARR_2D(arr, value, row, column)    \
do{ \
    for(size_t i_in_FILL_ARR_2D = 0; i_in_FILL_ARR_2D < row; i_in_FILL_ARR_2D++){  \
        for(size_t j_in_FILL_ARR_2D = 0; j_in_FILL_ARR_2D < column; j_in_FILL_ARR_2D++){ \
            arr[i_in_FILL_ARR_2D][j_in_FILL_ARR_2D] = value;  \
        }   \
    }   \
}while(0)

static inline bool is_small_endian(void)
{
	union w {
		int a;
		char b;
	} c;
	c.a = 1;
	return ( c.b == 1 ); // 小端返回TRUE,大端返回FALSE
}

// 指定范围生成随机数
#define RAND(min, max)  \
({  \
    struct timespec _t_temp_in_RAND = {0, 0}; \
    clock_gettime(CLOCK_MONOTONIC, &_t_temp_in_RAND);  \
    /* 初始化随机数发生器 */ \
    srand((unsigned) _t_temp_in_RAND.tv_nsec);     \
    int _ret_int_RAND = min + rand() % (max - min + 1);   \
    _ret_int_RAND;    \
})



typedef bool (*find_cmpfunc_t)(const void *current);

void *cfind_$(const void *start, const void *end, const void *target, int target_size);
// 在指定范围内查找目标, 是find的封装
#define cfind(start, end, target)    \
({  \
    __typeof(target) *_ret_val_in_cfind = NULL;   \
    __typeof(target) _target_in_cfind = target;   \
    _ret_val_in_cfind = (__typeof(target)*)cfind_$(start, end, &_target_in_cfind, sizeof(_target_in_cfind));    \
    _ret_val_in_cfind;    \
})

#ifdef __cplusplus
#define var_sign(var)   \
({  \
    STATIC_ASSERT(std::is_signed<__typeof(var)>::value == 1, "file:" __FILE__ " line:" TO_STRING(__LINE__) " should use signed var");    \
    int sign_in_var_sign = 0;   \
    if (var > 0){   \
        sign_in_var_sign = 1;   \
    }else if(var < 0){  \
        sign_in_var_sign = -1;  \
    }   \
    sign_in_var_sign;    \
})
#else
// 输入变量必须为有符号基本类型, 不能是指针, 不能是结构体实例, 不能是数组
#define var_sign(var)   \
({  \
    STATIC_ASSERT(IS_SIGNED(var) == 1, "file:" __FILE__ " line:" TO_STRING(__LINE__) " should not use unsigned var" ); \
    __typeof(var) tmp_in_var_sign;(void)tmp_in_var_sign;  \
    tmp_in_var_sign = 0;    /*should not use array or struct */\
    STATIC_ASSERT(NOT_PTR(var) || SIZE_NOT_EQU_PTR(var), "file:" __FILE__ " line:" TO_STRING(__LINE__) " should not use pointer" ); \
    int sign_in_var_sign = 0;   \
    if (var > 0){   \
        sign_in_var_sign = 1;   \
    }else if(var < 0){  \
        sign_in_var_sign = -1;  \
    }   \
    sign_in_var_sign;    \
})

#endif

#define IS_UNSIGNED(a)  (   \
__builtin_types_compatible_p(__typeof(a), _Bool) || \
__builtin_types_compatible_p(__typeof(a), unsigned long ) || \
__builtin_types_compatible_p(__typeof(a), wchar_t ) || \
__builtin_types_compatible_p(__typeof(a), uint8_t) || \
__builtin_types_compatible_p(__typeof(a), uint16_t) || \
__builtin_types_compatible_p(__typeof(a), uint32_t ) || \
__builtin_types_compatible_p(__typeof(a), uint64_t )    \
)
#define IS_SIGNED(a)   \
({  \
    !IS_UNSIGNED(a); \
})



#define left_larger(a, b)   \
({  \
    STATIC_ASSERT(__builtin_types_compatible_p(__typeof(a), __typeof(b) ), "file:" __FILE__ " line:" TO_STRING(__LINE__) " must be same type" ); \
    int ret_val_in_left_larger = 0; \
    if( (a) > (b) ){    \
        ret_val_in_left_larger = 1; \
    }else{  \
        ret_val_in_left_larger = 0; \
    }   \
    ret_val_in_left_larger; \
})

#define left_larger_equ(a, b)   \
({  \
    STATIC_ASSERT(__builtin_types_compatible_p(__typeof(a), __typeof(b) ), "file:" __FILE__ " line:" TO_STRING(__LINE__) " must be same type" ); \
    int ret_val_in_left_larger_equ = 0; \
    if( (a) >= (b) ){    \
        ret_val_in_left_larger_equ = 1; \
    }else{  \
        ret_val_in_left_larger_equ = 0; \
    }   \
    ret_val_in_left_larger; \
})

#define left_smaller(a, b)          (!left_larger_equ(a, b))
#define left_smaller_equ(a, b)      (!left_larger(a, b))


#define IS_INTEGRAL(a)  \
(   \
__builtin_types_compatible_p(__typeof(a), _Bool) || \
__builtin_types_compatible_p(__typeof(a), char) || \
__builtin_types_compatible_p(__typeof(a), signed char ) || \
__builtin_types_compatible_p(__typeof(a), unsigned char ) || \
__builtin_types_compatible_p(__typeof(a), short) || \
__builtin_types_compatible_p(__typeof(a), unsigned short ) || \
__builtin_types_compatible_p(__typeof(a), int ) ||   \
__builtin_types_compatible_p(__typeof(a), unsigned int) ||   \
__builtin_types_compatible_p(__typeof(a), long ) ||   \
__builtin_types_compatible_p(__typeof(a), unsigned long ) ||   \
__builtin_types_compatible_p(__typeof(a), long long) ||   \
__builtin_types_compatible_p(__typeof(a), unsigned long long) \
)

#define IS_FLOATING_POINT(a)    \
(   \
__builtin_types_compatible_p(__typeof(a), float)  || \
__builtin_types_compatible_p(__typeof(a), double)  || \
__builtin_types_compatible_p(__typeof(a), long double)  \
)

// 性能会下降, 因为每次都用double计算
#define my_div(a, b)    \
({  \
    __typeof(a)   a_in_my_div = a;    \
    __typeof(b)   b_in_my_div = b;    \
    double ret_val_in_my_div;   \
    MY_UTILS_ASSERT(b_in_my_div != 0);  \
    ret_val_in_my_div = (double)a_in_my_div / (double)b_in_my_div;  \
    ret_val_in_my_div;  \
})
//================== 通用小函数或宏 end =============================


//================== crc 校验 =======================================
uint16_t crc16_modbus(uint8_t *puchMsg, uint16_t usDataLen)  ;
//================== crc 校验 =======================================
#ifdef __cplusplus
}
#endif



#endif // MY_UTILS_H__

